﻿using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace WPNextTools.NHelper
{
    public static class VisualTreeHelperExtensions
    {
        public static T GetFirstLogicalChildByType<T>(this FrameworkElement parent, string name, bool applyTemplates) where T : FrameworkElement
		{
			Queue<FrameworkElement> queue = new Queue<FrameworkElement>();
			queue.Enqueue(parent);
			while (queue.Count > 0)
			{
				FrameworkElement frameworkElement = queue.Dequeue();
				Control control = frameworkElement as Control;
				if (applyTemplates && control != null)
				{
					control.ApplyTemplate();
				}
				if (frameworkElement is T && frameworkElement != parent && (string.IsNullOrEmpty(name) || frameworkElement.Name == name))
				{
					return (T)((object)frameworkElement);
				}
				using (IEnumerator<FrameworkElement> enumerator = Enumerable.OfType<FrameworkElement>(frameworkElement.GetVisualChildren()).GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						FrameworkElement current = enumerator.Current;
						queue.Enqueue(current);
					}
				}
			}
			return default(T);
		}

        public static T GetFirstLogicalChildByType<T>(this FrameworkElement parent, bool applyTemplates) where T : FrameworkElement
        {
            return parent.GetFirstLogicalChildByType<T>(null, applyTemplates);
        }

        public static IEnumerable<T> GetLogicalChildrenByType<T>(this FrameworkElement parent, bool applyTemplates) where T : FrameworkElement
        {
            if (applyTemplates && parent is Control)
            {
                ((Control)parent).ApplyTemplate();
            }
            Queue<FrameworkElement> queue = new Queue<FrameworkElement>(Enumerable.OfType<FrameworkElement>(parent.GetVisualChildren()));
            while (queue.Count > 0)
            {
                FrameworkElement frameworkElement = queue.Dequeue();
                if (applyTemplates && frameworkElement is Control)
                {
                    ((Control)frameworkElement).ApplyTemplate();
                }
                if (frameworkElement is T)
                {
                    yield return (T)((object)frameworkElement);
                }
                using (IEnumerator<FrameworkElement> enumerator = Enumerable.OfType<FrameworkElement>(frameworkElement.GetVisualChildren()).GetEnumerator())
                {
                    while (enumerator.MoveNext())
                    {
                        FrameworkElement current = enumerator.Current;
                        queue.Enqueue(current);
                    }
                }
            }
            yield break;
        }

        public static IEnumerable<FrameworkElement> GetVisualChildren(this FrameworkElement root)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(root); i++)
            {
                yield return VisualTreeHelper.GetChild(root, i) as FrameworkElement;
            }
            yield break;
        }

        public static T FindAncestor<T>(this DependencyObject obj) where T : DependencyObject
        {
            while (obj != null)
            {
                T o = obj as T;
                if (o != null)
                    return o;
                obj = VisualTreeHelper.GetParent(obj);
            }
            return null;
        }
    }
}
